package sfin.service;

import static org.apache.commons.lang.StringUtils.isBlank;

import java.io.Serializable;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.ResourceBundle;

import javax.persistence.PersistenceException;

import org.hibernate.exception.ConstraintViolationException;

import sfin.swt.data.DateData;
import sfin.swt.data.LancamentoData;
import sfin.swt.data.LancamentoTableData;
import sfin.swt.data.ProjecaoCreditoData;
import sfin.swt.data.ResumoData;
import sfin.swt.events.ServiceChangeEvent;
import sfin.swt.events.ServiceChangeListener;
import sfin.swt.exception.StatizoException;
import sfin.swt.filter.LancamentoFilter;
import sfin.swt.util.FormatterUtil;
import br.com.statizo.financeiro.core.repository.impl.LancamentoRepository;
import br.com.statizo.financeiro.domain.entity.impl.CartaoCredito;
import br.com.statizo.financeiro.domain.entity.impl.Categoria;
import br.com.statizo.financeiro.domain.entity.impl.ContaCorrente;
import br.com.statizo.financeiro.domain.entity.impl.Lancamento;
import br.com.statizo.financeiro.domain.enums.ColorConfigType;
import br.com.statizo.financeiro.domain.enums.FormaPagamento;
import br.com.statizo.financeiro.domain.enums.GrupoLancamento;

public class LancamentoService extends AbstractService implements ServiceChangeListener{

	private List<Lancamento> lancamentos;

	private CategoriaService categoriaService;
	private ContaService contaService;
	private CartaoService cartaoService;

	private LancamentoRepository lancamentoRepository;
	private PeriodoService periodoService;
	private ConfigService configService;

	public LancamentoService(ResourceBundle bundle, FormatterUtil formatterUtil, LancamentoRepository lancamentoRepository, 
			PeriodoService periodoService, ContaService contaService, ConfigService configService) {
		super(bundle, formatterUtil);
		this.lancamentoRepository = lancamentoRepository;
		this.periodoService = periodoService;
		this.contaService = contaService;
		this.configService = configService;
		refreshList();
		sort();
	}

	private void refreshList() {
		Serializable accountId = contaService.getApplicationAccountId();
		lancamentos = lancamentoRepository.getListBy(periodoService.getApplicationMonth() + 1, periodoService.getApplicationYear(), accountId);
		notifyListeners();
	}

	public Lancamento getAt(int index){
		return lancamentos.get(index);
	}

	public void sort(){
		lancamentos.sort((l1,l2) -> l1.getDataPagamento().compareTo(l2.getDataPagamento()));
	}


	public LancamentoData getLancamentoDataAt(int index){
		return toLancamentoData(lancamentos.get(index));
	}

	protected LancamentoData toLancamentoData(Lancamento lancamento){

		lancamento = lancamentoRepository.merge(lancamento);

		LancamentoData lancamentoData = new LancamentoData();
		lancamentoData.dataDivida = new DateData();
		lancamentoData.dataPgto = new DateData();

		Calendar calendar = lancamento.getDataDivida();
		lancamentoData.dataDivida.day = calendar.get(Calendar.DATE);
		lancamentoData.dataDivida.month = calendar.get(Calendar.MONTH);
		lancamentoData.dataDivida.year = calendar.get(Calendar.YEAR);

		calendar = lancamento.getDataPagamento();
		lancamentoData.dataPgto.day = calendar.get(Calendar.DATE);
		lancamentoData.dataPgto.month = calendar.get(Calendar.MONTH);
		lancamentoData.dataPgto.year = calendar.get(Calendar.YEAR);

		lancamentoData.descricao = lancamento.getDescricao();
		lancamentoData.valor =  formatterUtil.getStringValue(lancamento.getValor());
		lancamentoData.pago = lancamento.isPago();

		lancamentoData.categoria = categoriaService.indexOf( lancamento.getCategoria() );
		lancamentoData.conta = contaService.indexOf( lancamento.getConta() );
		lancamentoData.formaPgto = lancamento.getFormaPagamento().ordinal();
		lancamentoData.parcelado = lancamento.isParcela() || lancamento.isPrimeiraParcela();


		CartaoCredito cartao = lancamento.getCartao();
		if(cartao != null){
			lancamentoData.cartaoCredito = cartaoService.indexOf(cartao);
		}else{
			lancamentoData.cartaoCredito = -1;
		}

		return lancamentoData;
	}

	@Deprecated
	//FIXME Este método irá para LancamentoFilterService.
	public List<Integer> getLancamentos(LancamentoFilter filter){

		List<Integer> filtered = new ArrayList<Integer>();

		int mes = periodoService.getApplicationMonth();
		int ano = periodoService.getApplicationYear();

		for(int i = 0; i<lancamentos.size(); i++){

			Lancamento lancamento = lancamentos.get(i);
			boolean textOk = true;

			String filterText = filter.getText();
			if(!isBlank(filterText)){
				String normalizedDescr = lancamento.getDescricao().toLowerCase();
				String normalizedTextFilter = filter.getText().toLowerCase();
				textOk = normalizedDescr.matches(".*"+normalizedTextFilter+".*");
			}

			if(lancamento.isSaldo()){

				if(filter.getReceita() == null){

					if(textOk)
						filtered.add(i);	

				}else{

					boolean saldoSaida = lancamento.isSaldoSaida(mes, ano);
					boolean recOk = (filter.getReceita() && !saldoSaida) || (!filter.getReceita() && saldoSaida);

					if(recOk && textOk)
						filtered.add(i);
				}

			}else{
				boolean cardOk = filter.getCartao() == null || (Boolean.TRUE.equals(filter.getCartao()) && lancamento.getCartao() != null)
						|| (Boolean.FALSE.equals(filter.getCartao()) && lancamento.getCartao() == null);

				boolean moneyOk = filter.getDebito() == null || (Boolean.TRUE.equals(filter.getDebito()) && FormaPagamento.DINHEIRO.equals(lancamento.getFormaPagamento()));

				boolean checkOk = filter.getCheque() == null || (Boolean.TRUE.equals(filter.getCheque()) && FormaPagamento.CHEQUE.equals(lancamento.getFormaPagamento()));

				boolean transfOk = filter.getTranferencia() == null || (Boolean.TRUE.equals(filter.getTranferencia()) && FormaPagamento.TRANSFERENCIA.equals(lancamento.getFormaPagamento()));

				boolean pgOk = filter.getPg() == null || (Boolean.TRUE.equals(filter.getPg()) && lancamento.isPago())
						|| (Boolean.FALSE.equals(filter.getPg()) && !lancamento.isPago());

				boolean recOk = filter.getReceita() == null || (Boolean.TRUE.equals(filter.getReceita()) && lancamento.isReceita())
						|| (Boolean.FALSE.equals(filter.getReceita()) && !lancamento.isReceita());

				boolean agendOk = !filter.isAgend() || (filter.isAgend() && lancamento.isAgendado());


				if(cardOk && moneyOk && checkOk && transfOk && pgOk && recOk && textOk && agendOk)
					filtered.add(i);
			}

		}

		return filtered;

	}

	public Boolean getSituacoes(int[] indices){
		if(indices.length == 0)
			return null;
		Boolean paid = lancamentos.get(indices[0]).isPago();
		for(int i = 1; i<indices.length; i++){
			if(lancamentos.get(indices[i]).isPago() != paid){
				return null;
			}
		}
		return paid;
	}


	public void putBackgroundColor(LancamentoTableData tableData){

		int[] bg = null;
		int[] fg = null;

		if(tableData.receita){
			if(tableData.agendado){
				bg = configService.getBackgroundColor(ColorConfigType.RECEITA_AGE_BG);
				fg = configService.getBackgroundColor(ColorConfigType.RECEITA_AGE_FG);
			}else if(tableData.pg){
				bg = configService.getBackgroundColor(ColorConfigType.RECEITA_PG_BG);
				fg = configService.getBackgroundColor(ColorConfigType.RECEITA_PG_FG);
			}else{
				bg = configService.getBackgroundColor(ColorConfigType.RECEITA_NPG_BG);
				fg = configService.getBackgroundColor(ColorConfigType.RECEITA_NPG_FG);
			}
		}else{

			if(tableData.investimento){

				if(tableData.agendado){
					bg = configService.getBackgroundColor(ColorConfigType.INVEST_AGE_BG);
					fg = configService.getBackgroundColor(ColorConfigType.INVEST_AGE_FG);
				}else if(tableData.pg){
					bg = configService.getBackgroundColor(ColorConfigType.INVEST_PG_BG);
					fg = configService.getBackgroundColor(ColorConfigType.INVEST_PG_FG);
				}else{
					bg = configService.getBackgroundColor(ColorConfigType.INVEST_NPG_BG);
					fg = configService.getBackgroundColor(ColorConfigType.INVEST_PG_FG);
				}

			}else{

				if(tableData.agendado){
					bg = configService.getBackgroundColor(ColorConfigType.DESPESA_AGE_BG);
					fg = configService.getBackgroundColor(ColorConfigType.DESPESA_AGE_FG);
				}else if(tableData.pg){
					bg = configService.getBackgroundColor(ColorConfigType.DESPESA_PG_BG);
					fg = configService.getBackgroundColor(ColorConfigType.DESPESA_PG_FG);
				}else{
					bg = configService.getBackgroundColor(ColorConfigType.DESPESA_NPG_BG);
					fg = configService.getBackgroundColor(ColorConfigType.DESPESA_NPG_FG);
				}

			}

		}

		tableData.background = bg;
		tableData.foreground = fg;

	}

	public LancamentoTableData getAsTableData(int index){

		LancamentoTableData data = new LancamentoTableData();
		Lancamento lancamento = lancamentoRepository.merge(lancamentos.get(index));

		data.dtPgto =  formatterUtil.getFormattedDate(lancamento.getDataPagamento());
		data.dtDivida =  formatterUtil.getFormattedDate(lancamento.getDataDivida());
		data.descricao = lancamento.getDescricao();
		data.saldo = lancamento.isSaldo();
		data.pg = lancamento.isPago();
		data.valor = formatterUtil.getCurrencyString(lancamento.getValor());
		data.valorMeta = lancamento.getValor();
		data.investimento = lancamento.isInvestimento();

		if(lancamento.isSaldo()){

		}else{

			data.categoria = lancamento.getCategoria().getNome();
			data.natureza = lancamento.getCategoria().getGrupo().getNome();
			data.formaPgto = bundle.getString(lancamento.getFormaPagamento().getNome());

			if(FormaPagamento.TRANSFERENCIA.equals(lancamento.getFormaPagamento())){
				data.transferenciaPara = bundle.getString("strings.arrow-to-right") + lancamento.getContaTransferencia().getApelido();
			}else{
				data.transferenciaPara = null;
			}

			CartaoCredito cartao = lancamento.getCartao();
			if(cartao != null){
				data.cartaoDeCredito = lancamento.getCartao().getNome();
			}else{
				data.cartaoDeCredito = null;
			}

			if(data.transferenciaPara == null && data.cartaoDeCredito == null){

				ContaCorrente conta = lancamento.getConta();
				data.contaCorrente = conta.getApelido();

			}

			data.receita = lancamento.getCategoria().getGrupo().isReceita();
			data.agendado = lancamento.isAgendado();
		}

		putBackgroundColor(data);
		return data;
	}

	public void liberarSaldo() throws StatizoException{

		lancamentoRepository.entityManagerRefresh();
		lancamentoRepository.beginTransaction();

		try{

			int mes = periodoService.getApplicationMonth();
			int ano = periodoService.getApplicationYear();

			lancamentoRepository.liberarSaldo(mes, ano);
			lancamentoRepository.commit();

			refreshList();

		}catch(Exception e){
			lancamentoRepository.rollBack();
			throw new StatizoException(e.getMessage());
		}

	}

	public void gerarSaldoDoMesAtual() throws StatizoException{

		List<String> errors = new ArrayList<String>();

		double rec = 0.0d;
		double des = 0.0d;

		int mes = periodoService.getApplicationMonth();
		int ano = periodoService.getApplicationYear();

		ContaCorrente conta = contaService.getCurrentAccount();

		if(conta == null){
			errors.add(bundle.getString("lancamento.saldo.current-account-null"));
		}

		for(int i = 0; i<this.lancamentos.size(); i++){

			Lancamento lanc = lancamentos.get(i);

			if(lanc.isSaldoSaida(mes, ano)){
				errors.add(bundle.getString("lancamento.saldo.duplicate.error"));
				break;
			}

			if(lanc.isSaldo()){
				rec += lanc.getValor();
			}else{
				if(lanc.isReceita()){
					rec += lanc.getValor();
				}else if(lanc.isDespesa()){
					des += lanc.getValor();
				}
			}

		}

		if(errors.isEmpty()){

			double saldo = rec - des;

			lancamentoRepository.entityManagerRefresh();
			lancamentoRepository.beginTransaction();

			try{

				Lancamento lancamento = new Lancamento();

				Calendar calendar = new GregorianCalendar(periodoService.getApplicationYear(), 
						periodoService.getApplicationMonth(),periodoService.getLastDayOfMonth());
				lancamento.setDataDivida(calendar);
				calendar = new GregorianCalendar(periodoService.getApplicationYear(), periodoService.getApplicationMonth() + 1, 1);
				lancamento.setDataPagamento(calendar);

				lancamento.setDescricao(bundle.getString("lancamento.saldo.desc"));
				lancamento.setSaldo(true);
				lancamento.setConta(conta);
				lancamento.setPago(true);
				lancamento.setValor(saldo);
				lancamentoRepository.merge(lancamento);
				lancamentoRepository.commit();

				lancamentos.add(lancamento);

				notifyListeners();

			}catch(Exception e){
				e.printStackTrace();
				errors.add(e.getMessage());
				throw new StatizoException(errors);
			}

		}else{
			throw new StatizoException(errors);
		}
	}

	public boolean isLancamentosFinalizados(){
		int mes = periodoService.getApplicationMonth();
		int ano = periodoService.getApplicationYear();
		boolean finalizado = false;
		for(int i = 0; i<lancamentos.size(); i++){
			if(lancamentos.get(i).isSaldoSaida(mes, ano)){
				finalizado = true;
				break;
			}
		}
		return finalizado;
	}

	public void excluir(int[] indices, boolean forced) throws StatizoException{

		List<String> errors = new ArrayList<String>();

		try{

			int realIndex;

			lancamentoRepository.entityManagerRefresh();
			lancamentoRepository.beginTransaction();

			boolean dependencyAdded = false;
			for (int i = 0; i < indices.length; i++) {
				realIndex = indices[i];
				Lancamento removed = lancamentoRepository.merge(lancamentos.get(realIndex));

				if(forced){

					boolean primeiraParcela = removed.isPrimeiraParcela();
					if(primeiraParcela){
						lancamentoRepository.deleteChilds(removed.getId());	
						lancamentoRepository.remove(removed.getId());
					}else{
						boolean nParcela = removed.isParcela();
						if(nParcela){
							Serializable idPrimeiraParcela = removed.getPrimeiraParcela().getId();
							lancamentoRepository.deleteChilds(idPrimeiraParcela);
							lancamentoRepository.remove(idPrimeiraParcela);
						}
					}
				}else{
					if(removed.isParcela() || removed.isPrimeiraParcela()){

						if(!dependencyAdded){
							errors.add(bundle.getString("entry.table.action.exclusion.error.dependency"));	
							dependencyAdded = true;

						}
					}else{
						lancamentoRepository.remove(removed.getId());
					}

				}
			}

			if(errors.isEmpty()){
				lancamentoRepository.commit();
				refreshList();
			}else{
				lancamentoRepository.rollBack();
				throw new StatizoException(errors); 
			}

		}catch(PersistenceException e){
			lancamentoRepository.rollBack();
			if(e.getCause() instanceof ConstraintViolationException){
				errors.add(bundle.getString("entry.table.action.exclusion.error.dependency"));				
			}else{
				errors.add(MessageFormat.format(bundle.getString("application.error.generic"), e.getMessage()));
			}
			throw new StatizoException(errors);
		}

	}


	public void marcarPago(int[] indices, boolean pago) throws StatizoException{

		List<String> errors = new ArrayList<String>();

		lancamentoRepository.entityManagerRefresh();
		lancamentoRepository.beginTransaction();
		try{
			int realIndex = 0;
			for(int i = 0; i<indices.length; i++){
				realIndex = indices[i];
				lancamentoRepository.setPago(lancamentos.get(realIndex).getId(), pago);
			}
			for(int i = 0; i<indices.length; i++){
				realIndex = indices[i];
				lancamentos.get(realIndex).setPago(pago);
			}
			lancamentoRepository.commit();
		}catch(Exception e){
			lancamentoRepository.rollBack();
			errors.add(e.getMessage());
			throw new StatizoException(errors);
		}

		refreshList();

	}

	public void marcarAgendado(int[] indices, boolean agendado) throws StatizoException{

		List<String> errors = new ArrayList<String>();

		lancamentoRepository.entityManagerRefresh();
		lancamentoRepository.beginTransaction();
		try{
			int realIndex = 0;
			for(int i = 0; i<indices.length; i++){
				realIndex = indices[i];
				lancamentoRepository.setAgendado(lancamentos.get(realIndex).getId(), agendado);
			}
			for(int i = 0; i<indices.length; i++){
				realIndex = indices[i];
				lancamentos.get(realIndex).setAgendado(agendado);
			}
			lancamentoRepository.commit();
		}catch(Exception e){
			lancamentoRepository.rollBack();
			errors.add(e.getMessage());
			throw new StatizoException(errors);
		}
		notifyListeners();
	}




	public int save(int realIndex, DateData dataPgto, DateData dataDiv,int categoriaIndex, String descricao, String valor, int contaIndex,
			int contaTrasferenciaIndex,int formaPgtoIndex, int cartaoIndex, String parcelas, boolean pago,boolean parcelado, boolean replicado, boolean vinc) throws StatizoException {

		List<String> messages = new ArrayList<String>();

		FormaPagamento formaPgto = null;
		Categoria categoria = null;
		Calendar pgtoDate = null;
		Calendar factDate = null;
		ContaCorrente conta = null;
		ContaCorrente contaTransferencia = null;
		CartaoCredito cartao = null;

		double val = 0.0d;
		int qtdParcs = 0;

		int mes = dataPgto.month;
		int ano = dataPgto.year;

		boolean fechado = lancamentoRepository.isSaldoExistente(mes, ano);

		if(fechado){
			messages.add(bundle.getString("lancamentos.end.message"));
		}

		if(!isBlank(parcelas)){
			try{
				qtdParcs = formatterUtil.parseInt(parcelas,0);
			}catch(Exception e){
				messages.add(e.getMessage());
			}
		}

		if((parcelado || replicado) && qtdParcs < 2){
			messages.add(bundle.getString("lancamento.qtdparc.required.msg"));
		}

		if(isBlank(descricao)){
			messages.add(bundle.getString("lancamento.descricao.required.msg"));
		}

		if(categoriaIndex < 0){
			messages.add(bundle.getString("lancamento.categ.required.msg"));
		}else{
			try{
				categoria = categoriaService.getAt(categoriaIndex);
			}catch(Exception e){
				messages.add(bundle.getString("lancamento.categ.required.msg"));				
			}
		}

		if(contaIndex < 0){
			messages.add(bundle.getString("lancamento.conta.required.msg"));
		}else{
			try{
				conta = contaService.getAt(contaIndex);
			}catch(Exception e){
				messages.add(bundle.getString("lancamento.conta.required.msg"));				
			}
		}

		if(formaPgtoIndex < 0){
			messages.add(bundle.getString("lancamento.formapgto.required.msg"));
		}else{
			try{
				formaPgto = FormaPagamento.values()[formaPgtoIndex];
			}catch(Exception e){
				messages.add(bundle.getString("lancamento.formapgto.required.msg"));				
			}
		}

		if(isBlank(valor)){
			messages.add(bundle.getString("lancamento.valor.required.msg"));
		}else{
			try {
				val = formatterUtil.parseDouble(valor,0);
				if(val <= 0.0d){
					messages.add(bundle.getString("application.messages.error.onsave.lancamento.value.invalid"));			
				}

			} catch (ParseException e) {
				messages.add(bundle.getString("application.messages.error.onsave.lancamento.value.invalid"));					
			}
		}

		if(cartaoIndex >= 0){
			try{
				cartao = cartaoService.getAt(cartaoIndex);
			}catch(Exception e){
				messages.add(bundle.getString("lancamento.cartao.required.msg"));				
			}
		}

		if(contaTrasferenciaIndex >=0){
			try{
				contaTransferencia = contaService.getAt(contaTrasferenciaIndex);
			}catch(Exception e){
				messages.add(bundle.getString("lancamento.conta-transf.required.msg"));				
			}
		}

		pgtoDate = new GregorianCalendar(dataPgto.year, dataPgto.month, dataPgto.day);
		factDate = new GregorianCalendar(dataDiv.year, dataDiv.month, dataDiv.day);

		if(pgtoDate.before(factDate)){
			messages.add(bundle.getString("application.messages.error.onsave.lancamento.date.pay-before-fact"));			
		}

		if(FormaPagamento.CARTAO_CREDITO.equals(formaPgto)){
			if(cartao == null){
				messages.add(bundle.getString("lancamento.cartao.required.msg"));
			}
		}else if(FormaPagamento.TRANSFERENCIA.equals(formaPgto)){
			if(contaTransferencia == null){
				messages.add(bundle.getString("lancamento.conta-transf.required.msg"));
			}
		}

		if(messages.isEmpty()){

			List<Lancamento> parcs = null;

			Lancamento lancamento = realIndex >=0 ? lancamentos.get(realIndex) : new Lancamento();
			lancamento.setDescricao(descricao);
			lancamento.setDataDivida(factDate);
			lancamento.setDataPagamento(pgtoDate);
			lancamento.setValor(val);
			lancamento.setPago(pago);
			lancamento.setCategoria(categoria);
			lancamento.setConta(conta);
			lancamento.setFormaPagamento(formaPgto);
			lancamento.setCartao(cartao);
			lancamento.setContaTransferencia(contaTransferencia);

			if(contaTransferencia != null)
				lancamento.setContaTransferencia(contaTransferencia);

			if((parcelado || replicado) && realIndex == -1){
				parcs = parcelar(lancamento,qtdParcs, parcelado,replicado,messages);

				if(messages.isEmpty()){

					try{

						lancamentoRepository.entityManagerRefresh();
						lancamentoRepository.beginTransaction();

						Lancamento first = parcs.get(0);
						first = lancamentoRepository.merge(first);
						for(int i = 1; i<parcs.size(); i++){
							Lancamento parcela = parcs.get(i);

							if(vinc)
								parcela.setPrimeiraParcela(first);

							lancamentoRepository.merge(parcela);
						}

						lancamentoRepository.commit();

						if(!lancamentos.contains(first)){
							lancamentos.add(first);
						}

						sort();
						notifyListeners();
						return lancamentos.indexOf(first);

					}catch(Exception e){
						messages.add(e.getMessage());
						lancamentoRepository.rollBack();
						throw new StatizoException(messages);
					}


				}else{
					throw new StatizoException(messages);
				}
			}else{
				lancamentoRepository.entityManagerRefresh();
				lancamentoRepository.beginTransaction();
				try{
					lancamento = lancamentoRepository.merge(lancamento);
					lancamentoRepository.commit();

					if(!lancamentos.contains(lancamento)){
						lancamentos.add(lancamento);
					}

					sort();
					notifyListeners();
					return lancamentos.indexOf(lancamento);

				}catch(Exception e){
					messages.add(e.getMessage());
					lancamentoRepository.rollBack();
					throw new StatizoException(messages);
				}
			}
		}else{

			throw new StatizoException(messages);

		}

	}

	public void setCartaoService(CartaoService cartaoService) {
		this.cartaoService = cartaoService;
	}

	public void setCategoriaService(CategoriaService categoriaService) {
		this.categoriaService = categoriaService;
	}



	protected Lancamento getCopy(Lancamento lancamento){
		Lancamento newLancamento = new Lancamento();
		newLancamento.setCategoria(lancamento.getCategoria());
		newLancamento.setCartao(lancamento.getCartao());
		newLancamento.setFormaPagamento(lancamento.getFormaPagamento());
		newLancamento.setDescricao(lancamento.getDescricao());
		newLancamento.setObservacao(lancamento.getObservacao());
		newLancamento.setConta(lancamento.getConta());
		newLancamento.setContaTransferencia(lancamento.getContaTransferencia());
		return newLancamento;
	}

	public List<Lancamento> parcelar(Lancamento lancamento, int qtd, boolean parcelado, boolean replicado, List<String> messages) throws StatizoException{

		List<String> errors = new ArrayList<String>();

		try{

			List<Lancamento> lancamentos = new ArrayList<Lancamento>(qtd);

			double valorParc = lancamento.getValor();
			if(parcelado)
				valorParc /= qtd;

			Calendar calendar = lancamento.getDataPagamento();

			lancamento.setValor(valorParc);

			lancamentos.add(lancamento);

			Calendar newCalendar;
			for(int i = 1; i<qtd; i++){
				newCalendar = new GregorianCalendar(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),calendar.get(Calendar.DATE));
				newCalendar.add(Calendar.MONTH, i);
				Lancamento newLancamento = getCopy(lancamento);
				newLancamento.setValor(valorParc);
				newLancamento.setDataPagamento(newCalendar);
				newLancamento.setDataDivida(newCalendar);
				lancamentos.add(newLancamento);
			}

			return lancamentos;

		}catch(Exception e){
			errors.add(e.getMessage());
			throw new StatizoException(errors);
		}

	}

	public double getSum(int[] indices){
		double sum = 0.0d;
		int mes = periodoService.getApplicationMonth();
		int ano = periodoService.getApplicationYear();

		for(int i = 0; i<indices.length; i++){
			Lancamento lancamento = lancamentos.get(indices[i]);

			if(lancamento.isSaldo()){

				if(lancamento.isSaldoSaida(mes, ano)){
					sum -= lancamento.getValor();
				}else{
					sum += lancamento.getValor();
				}

			}else{

				if(lancamento.isDespesa()){
					sum -= lancamento.getValor();	
				}else{
					sum += lancamento.getValor();					
				}

			}

		}
		return sum;
	}

	@Override
	public void changed(ServiceChangeEvent event) {
		refreshList();
	}

	public ResumoData getResumoFinanceiroData(){

		double dFix,dVar, dAd, dEx, inv, rec, card, sal;
		dFix = dVar = dAd = dEx = inv = rec = card = sal = 0.0d;

		double invRec,invDes,des,dTotalRec,dTotalDes,cardRec, cardDes, dFixRec, dFixDes, dVarRec, dVarDes, dAdRec, dAdDes, dExRec, dExDes;
		invRec = invDes = des = dTotalRec = dTotalDes = cardRec = cardDes = dFixRec = dFixDes = dVarRec = dVarDes = dAdRec = dAdDes = dExRec = dExDes = 0.0d;

		double pg,npg,curSld;
		pg = npg = curSld = 0.0d;

		double saldoEntrada, saldoSaida;
		saldoEntrada = saldoSaida = 0;

		ResumoData resumoData = null;

		int mes = periodoService.getApplicationMonth();
		int ano = periodoService.getApplicationYear();

		for(Lancamento lanc:lancamentos){
			double val = lanc.getValor();

			if(lanc.isSaldo()){

				if(lanc.isSaldoSaida(mes, ano)){

					saldoSaida += lanc.getValor();
					pg+=val;

				}else{

					saldoEntrada += lanc.getValor();

				}

			}else{

				if(lanc.isDespesa()){

					GrupoLancamento grupo = lanc.getCategoria().getGrupo();

					boolean pago = lanc.isPago();

					if(grupo == GrupoLancamento.DESPESA_FIXA){
						dFix += val;
					}else if(grupo == GrupoLancamento.DESPESA_VARIAVEL){
						dVar += val;
					}else if(grupo == GrupoLancamento.DESPESA_ADICIONAL){
						dAd += val;
					}else if(grupo == GrupoLancamento.DESPESA_EXTRA){
						dEx += val;
					}else if(grupo == GrupoLancamento.INVESTIMENTO){
						inv += val;
					}

					if(pago){
						pg += val;
					}
					
					if(lanc.isCartao()){
						card += val;
					}

				}else{

					rec += lanc.getValor();
					
					if(lanc.isCartao()){
						card -= val;
					}
						
				}


			}

		}

		des = dFix + dVar + dAd + dEx + inv + saldoSaida;
		rec += saldoEntrada;

		dTotalRec = (des / rec) * 100;
		dTotalDes = (des / rec) * 100;

		cardDes = (card / des) * 100;
		cardRec = (card / rec) * 100;

		dFixRec = (dFix / rec) * 100;
		dFixDes = (dFix / des) * 100;

		dVarRec = (dVar / rec) * 100;
		dVarDes = (dVar / des) * 100;

		dAdRec = (dAd / rec) * 100;
		dAdDes = (dAd / des) * 100;

		dExRec = (dEx / rec) * 100;
		dExDes = (dEx / des) * 100;

		invRec = (inv / rec) * 100;
		invDes = (inv / des) * 100;

		npg = des - pg;
		curSld = rec - pg;

		sal = rec - des;

		resumoData = new ResumoData();

		resumoData.receita =formatterUtil.getCurrencyString(rec);
		resumoData.investimento = formatterUtil.getCurrencyString(inv);

		resumoData.investimentoPercRec = formatterUtil.getPercentString(invRec);
		resumoData.investimentoPercDes = formatterUtil.getPercentString(invDes);

		resumoData.despesaFixa =formatterUtil.getCurrencyString(dFix);
		resumoData.despesaVariavel =formatterUtil.getCurrencyString(dVar);
		resumoData.despesaAdicional =formatterUtil.getCurrencyString(dAd);
		resumoData.despesaExtra =formatterUtil.getCurrencyString(dEx);

		resumoData.despesaFixaPercRec =formatterUtil.getPercentString(dFixRec);
		resumoData.despesaFixaPercDes =formatterUtil.getPercentString(dFixDes);

		resumoData.despesaVariavelPercRec =formatterUtil.getPercentString(dVarRec);
		resumoData.despesaVariavelPercDes =formatterUtil.getPercentString(dVarDes);

		resumoData.despesaAdicionalPercRec =formatterUtil.getPercentString(dAdRec);
		resumoData.despesaAdicionalPercDes =formatterUtil.getPercentString(dAdDes);

		resumoData.despesaExtraPercRec =formatterUtil.getPercentString(dExRec);
		resumoData.despesaExtraPercDes =formatterUtil.getPercentString(dExDes);

		resumoData.despesaTotal = formatterUtil.getCurrencyString(des);
		resumoData.despesaTotalPercDes = formatterUtil.getPercentString(dTotalDes);
		resumoData.despesaTotalPercRec = formatterUtil.getPercentString(dTotalRec);

		resumoData.cartaoCredito = formatterUtil.getCurrencyString(card);
		resumoData.cartaoCreditoPercDes = formatterUtil.getPercentString(cardDes);
		resumoData.cartaoCreditoPercRec = formatterUtil.getPercentString(cardRec);

		resumoData.saldo = formatterUtil.getCurrencyString(sal);

		resumoData.saldoConta = formatterUtil.getCurrencyString(curSld);
		resumoData.pago = formatterUtil.getCurrencyString(pg);
		resumoData.naoPago = formatterUtil.getCurrencyString(npg);

		resumoData.saldoEntrada = formatterUtil.getCurrencyString(saldoEntrada);
		resumoData.saldoSaida = formatterUtil.getCurrencyString(saldoSaida);

		return resumoData;

	}

	public boolean isLancamentoSaldo(int index){
		if(index == -1)
			return false;
		Lancamento lanc = lancamentoRepository.merge(lancamentos.get(index));
		return lanc.isSaldo();
	}


	public ProjecaoCreditoData projecaoData(){

		ProjecaoCreditoData data = new ProjecaoCreditoData();

		return data;
	}

	public boolean preventIndexOutException(int index){
		return lancamentos.size() > index;
	}


	public double getReceitaTotal(int mes, int ano){
		return lancamentoRepository.getReceitaTotal(mes, ano,contaService.getApplicationAccountId());
	}

	public double getDespesaTotal(int mes, int ano){
		return lancamentoRepository.getDespesaTotal(mes, ano,contaService.getApplicationAccountId());
	}

	public int getDefaultContaIndex(){
		return contaService.getCurrentApplicationAccountIndex();
	}

	public DateData getDefaultPgtoDate(){
		return configService.getDefaultPgtoDate();
	}
	
	
	public Double getMontante(int mes, int ano, GrupoLancamento grupo){
		return lancamentoRepository.obterMontante(mes, ano, grupo);
	}

	
	public List<Lancamento> getLancamentos(int mes, int ano, Serializable contaId){
		return lancamentoRepository.getListBy(mes, ano, contaId);
	}

}